package china.school.advised;


import org.springframework.aop.*;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;


/*
这个完整的示例包含了以下组件：
MyTargetObject：目标对象类，包含两个测试方法
MyMethodInterceptor：第一个拦截器实现，在方法执行前后添加日志
AnotherInterceptor：第二个拦截器实现，同样在方法执行前后添加日志
MyPointcut：自定义切入点，只匹配 doAnotherThing 方法
MyAdvice：自定义通知，配合切入点使用
运行结果将会显示所有拦截器按顺序执行的情况，其中 MyAdvice 只会在 doAnotherThing 方法执行时生效。
	这个例子展示了 Advised 接口的主要功能：
	在运行时动态添加通知和顾问
	检查代理配置状态（是否冻结）
	查询当前代理的所有顾问
	通过 ProxyFactory 创建和配置代理对象
 */


public class AdvisedTest {
	public static void main(String[] args) {
		// 创建目标对象实例
		MyTargetObject myTargetObject = new MyTargetObject();

		// 创建代理工厂并配置
		// ProxyFactory 是 Spring AOP 提供的一个便捷类，用于以编程方式创建 AOP 代理
		// setTarget(myTargetObject) 设置了要被代理的目标对象
		// addAdvice(new MyMethodInterceptor()) 添加了一个拦截器（通知），这是 AOP Alliance 的 Advice 接口的实现，会在目标方法执行前后进行拦截
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.setTarget(myTargetObject);
		proxyFactory.addAdvice(new MyMethodInterceptor());

		// 获取并操作 Advised 接口
		//proxyFactory.getProxy() 创建实际的代理对象，该代理对象同时实现了 Advised 接口
		//将代理对象强制转换为 Advised 接口，这样就可以在运行时动态操作代理配置
		//通过 getTargetSource() 获取 TargetSource 对象，并调用 getTargetClass() 方法获取目标类的信息
		Advised advised = (Advised) proxyFactory.getProxy();
		System.out.println("Proxy target class: " + advised.getTargetSource().getTargetClass());

		// 动态添加新的通知
		// 即使代理已经被创建，我们仍然可以通过 addAdvice() 方法向代理添加新的拦截器
		// 新添加的拦截器会应用到后续的所有方法调用上
		advised.addAdvice(new AnotherInterceptor());

		// 检查代理配置
		//isFrozen() 检查代理配置是否被冻结，如果配置被冻结，则不允许进一步修改
		//只有当配置未被冻结时，才允许通过 addAdvisor() 添加新的顾问
		//DefaultPointcutAdvisor 是 Advisor 接口的标准实现，它将切入点 (myPointcut) 和通知 (myAdvice) 组合在一起
		if (!advised.isFrozen()) {
			//自定义通知和切入点
			advised.addAdvisor(new DefaultPointcutAdvisor(new MyPointcut(), new MyAdvice()));
		}

		// 获取所有顾问
		// getAdvisors() 返回当前代理配置中所有的顾问数组
		//通过遍历这个数组，可以了解代理当前应用了哪些切面逻辑
		Advisor[] advisors = advised.getAdvisors();
		for (Advisor advisor : advisors) {
			System.out.println("Advisor: " + advisor);
		}

		// 测试代理对象
		System.out.println("\n=== 测试代理对象 ===");
//		MyTargetObject proxy = (MyTargetObject) proxyFactory.getProxy();
		//任何一个代理对象都可以强制转换为 Advised 接口
		MyTargetObject proxy = (MyTargetObject) advised;

		System.out.println("\n调用 doSomething() 方法:");
		proxy.doSomething();

		System.out.println("\n调用 doAnotherThing() 方法:");
		proxy.doAnotherThing();
	}
}
